#include "../include/arch/vectors.h"
#include <arch/gdt.h>
.macro isr_model vector, no_err_code=1
    .global __isr\vector
    .type __isr\vector, @function
    __isr\vector:
        .if \no_err_code
            pushl $0x0
        .endif
        pushl $\vector
        jmp interrupt_entry
.endm

.section .bss
    .align 16
    tmp_stack_bottom:
        .skip 128
    tmp_stack:

.text

    isr_model FAULT_DIVISION_ERROR
    isr_model FAULT_TRAP_DEBUG_EXCEPTION
    isr_model FAULT_NON_MASKABLE
    isr_model FAULT_BRIDGE_CHECK
    isr_model TRAP_OVERFLOW
    isr_model FAULT_BOUND_EXCEED
    isr_model FAULT_INVALID_OPCODE
    isr_model FAULT_NO_MATH_PROCESSOR
    isr_model ABORT_DOUBLE_FAULT, no_err_code=0
    isr_model FAULT_RESERVED_0
    isr_model FAULT_INVALID_TSS, no_err_code=0
    isr_model FAULT_SEG_NOT_PRESENT, no_err_code=0
    isr_model FAULT_STACK_SEG_FAULT, no_err_code=0
    isr_model FAULT_GENERAL_PROTECTION, no_err_code=0
    isr_model FAULT_PAGE_FAULT, no_err_code=0
    isr_model FAULT_RESERVED_1
    isr_model FAULT_X87_FAULT
    isr_model FAULT_ALIGNMENT_CHECK, no_err_code=0
    isr_model FAULT_MACHINE_CHECK
    isr_model FAULT_SIMD_FLOATING_POINT
    isr_model FAULT_VIRTUALIZATION
    isr_model FAULT_CONTROL_PROTECTION, no_err_code=0
    isr_model 22
    isr_model 23
    isr_model 24
    isr_model 25
    isr_model 26
    isr_model 27
    isr_model 28
    isr_model 29
    isr_model 30
    isr_model 31
    isr_model 32
    isr_model 33
    isr_model 34
    isr_model 35
    isr_model 36
    isr_model 37
    isr_model 38
    isr_model 39
    isr_model 40
    isr_model 41
    isr_model 42
    isr_model 43
    isr_model 44
    isr_model 45
    isr_model 46
    isr_model 47
    isr_model 48
    isr_model 49
    isr_model 50
    isr_model 51
    isr_model 52
    isr_model 53
    isr_model 54
    isr_model 55
    isr_model 56
    isr_model 57
    isr_model 58
    isr_model 59
    isr_model 60
    isr_model 61
    isr_model 62
    isr_model 63
    isr_model 64
    isr_model 65
    isr_model 66
    isr_model 67
    isr_model 68
    isr_model 69
    isr_model 70
    isr_model 71
    isr_model 72
    isr_model 73
    isr_model 74
    isr_model 75
    isr_model 76
    isr_model 77
    isr_model 78
    isr_model 79
    isr_model 80
    isr_model 81
    isr_model 82
    isr_model 83
    isr_model 84
    isr_model 85
    isr_model 86
    isr_model 87
    isr_model 88
    isr_model 89
    isr_model 90
    isr_model 91
    isr_model 92
    isr_model 93
    isr_model 94
    isr_model 95
    isr_model 96
    isr_model 97
    isr_model 98
    isr_model 99
    isr_model 100
    isr_model 101
    isr_model 102
    isr_model 103
    isr_model 104
    isr_model 105
    isr_model 106
    isr_model 107
    isr_model 108
    isr_model 109
    isr_model 110
    isr_model 111
    isr_model 112
    isr_model 113
    isr_model 114
    isr_model 115
    isr_model 116
    isr_model 117
    isr_model 118
    isr_model 119
    isr_model 120
    isr_model 121
    isr_model 122
    isr_model 123
    isr_model 124
    isr_model 125
    isr_model 126
    isr_model 127
    isr_model 128 # syscall 0x80
    isr_model 129
    isr_model 130
    isr_model 131
    isr_model 132
    isr_model 133
    isr_model 134
    isr_model 135
    isr_model 136
    isr_model 137
    isr_model 138
    isr_model 139
    isr_model 140
    isr_model 141
    isr_model 142
    isr_model 143
    isr_model 144
    isr_model 145
    isr_model 146
    isr_model 147
    isr_model 148
    isr_model 149
    isr_model 150
    isr_model 151
    isr_model 152
    isr_model 153
    isr_model 154
    isr_model 155
    isr_model 156
    isr_model 157
    isr_model 158
    isr_model 159
    isr_model 160
    isr_model 161
    isr_model 162
    isr_model 163
    isr_model 164
    isr_model 165
    isr_model 166
    isr_model 167
    isr_model 168
    isr_model 169
    isr_model 170
    isr_model 171
    isr_model 172
    isr_model 173
    isr_model 174
    isr_model 175
    isr_model 176
    isr_model 177
    isr_model 178
    isr_model 179
    isr_model 180
    isr_model 181
    isr_model 182
    isr_model 183
    isr_model 184
    isr_model 185
    isr_model 186
    isr_model 187
    isr_model 188
    isr_model 189
    isr_model 190
    isr_model 191
    isr_model 192
    isr_model 193
    isr_model 194
    isr_model 195
    isr_model 196
    isr_model 197
    isr_model 198
    isr_model 199
    isr_model 200
    isr_model 201
    isr_model 202
    isr_model 203
    isr_model 204
    isr_model 205
    isr_model 206
    isr_model 207
    isr_model 208
    isr_model 209
    isr_model 210
    isr_model 211
    isr_model 212
    isr_model 213
    isr_model 214
    isr_model 215
    isr_model 216
    isr_model 217
    isr_model 218
    isr_model 219
    isr_model 220
    isr_model 221
    isr_model 222
    isr_model 223
    isr_model 224
    isr_model 225
    isr_model 226
    isr_model 227
    isr_model 228
    isr_model 229
    isr_model 230
    isr_model 231
    isr_model 232
    isr_model 233
    isr_model 234
    isr_model 235
    isr_model 236
    isr_model 237
    isr_model 238
    isr_model 239
    isr_model 240
    isr_model 241
    isr_model 242
    isr_model 243
    isr_model 244
    isr_model 245
    isr_model 246
    isr_model 247
    isr_model 248
    isr_model 249
    isr_model 250
    isr_model 251
    isr_model 252
    isr_model 253
    isr_model 254
    isr_model 255
interrupt_entry:
    
    /* the stack layout after pushal
        ss and esp will present if privilege changes
    high--> (ss)    (stack bottom)
       68   (esp)
       64   eflags
       60   cs
       56   eip
       52   error code
       48   vector
       44   esp
       40   gs 
       36   fs
       32   es
       28   ds
       24   ebp
       20   edi
       16   esi
       12   edx
       8    ecx
       4    ebx
   low 0->  eax     (stack top)
    */
    cli
    cld
    pushl %esp

    subl $16, %esp
    movw %gs, 12(%esp)
    movw %fs, 8(%esp)
    movw %es, 4(%esp)
    movw %ds, (%esp)

    pushl %ebp
    pushl %edi
    pushl %esi
    pushl %edx
    pushl %ecx
    pushl %ebx
    pushl %eax

    movl 60(%esp), %eax // take cs
    andl $0x3, %eax     // check RPL
    jz 1f

    // switch to kernel if from user mode
    movw $SS_R0_DATA, %ax
    movw %ax, %gs
    movw %ax, %fs
    movw %ax, %ds
    movw %ax, %es

    movl (cur_proc), %eax
    movl 68(%esp), %ebx
    movl %ebx, 4(%eax) // save ustack. see struct process.ustack

1:
    movl %esp,%eax
    pushl %eax

    call interrupts_handler

    movl (%esp), %eax   // this will make iret_handle 
iret_handle:            // suitable for interrupt 
    movl %eax, %esp     // or switch_to

    # 发送EOI
    mov $0x20, %al
    out %al, $0x20

    popl %eax
    popl %ebx
    popl %ecx
    popl %edx
    popl %esi
    popl %edi
    popl %ebp
    
    movw   (%esp), %ds
    movw  4(%esp), %es
    movw  8(%esp), %fs
    movw 12(%esp), %gs
    movl 16(%esp), %esp

    addl $8, %esp // jump over error code and vector

    /**
    * if privilege changes while iret
    * the esp will pop 8 more bytes
    * so we need to adjust the tss
    */
    pushl %ecx
    movl 8(%esp), %ecx
    andl $0x3, %ecx // check RPL, 0x3 or 0x0
    shll %ecx, %ecx // 24 or 0
    orl  $16, %ecx // 24 or 16
    leal (%esp, %ecx, 1), %ecx
    movl %ecx, (tss + 4)
    popl %ecx
    
    iret


.global switch_to
switch_to:
    popl %ebx
    movl 8(%ebx), %ecx
    movl %cr3, %eax
    xorl %ecx, %eax
    jz 1f

    movl %ecx, %cr3
1:
    movl %ebx, cur_proc
    movl tmp_stack, %esp
    leal 12(%ebx), %eax
    jmp iret_handle